from django.db import transaction
from django.utils.timezone import now
from rest_framework.authentication import TokenAuthentication, BasicAuthentication
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.exceptions import ValidationError, NotFound
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response

from api.conf import order_status
from api.serializers.order_serializer import OrderAddSerializer, OrderResponseSerializer, OrderUpdateStatusSerializer, \
    OrderListRequestSerializer, OrderListResponseSerializer
from api.utils.paginator import get_page
from app.models import ProductSpec, Order, FMUser
from app.models.fm_user import USER_TYPE_SALES
from app.models.order import OrderProduct
from app.models.pre_order import PreOrder
from app.utils import generate_out_order_id


@api_view(['POST'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
@transaction.atomic
def add_order(request: Request):
    request_serializer = OrderAddSerializer(data=request.data)
    if request_serializer.is_valid():
        delivery_datetime = request_serializer.validated_data['delivery_datetime']  # 送货时间
        delivery_deadline_datetime = request_serializer.validated_data['delivery_deadline_datetime']  # 最迟送货时间
        address = request_serializer.validated_data['address']  # 送货地址
        remark = request_serializer.validated_data['remark']

        pre_order = PreOrder.objects.select_for_update().get(id=request_serializer.data["pre_order_id"])  # 预订单号
        order_sum = 0  # 订单价格
        all_deposit = 0
        pre_order_specs = pre_order.specs.all()  # 订单商品列表
        for pre_order_spec in pre_order_specs:
            if not pre_order_spec.spec.product.is_on_shell:
                raise ValidationError(detail=u'%s已下架' % pre_order_spec.spec.product.name)

            if not pre_order_spec.spec.is_on_shell:
                raise ValidationError(detail=u'%s已下架' % pre_order_spec.spec.name)

            if pre_order_spec.amount > pre_order_spec.spec.stock:
                raise ValidationError(detail=u'%s库存不足' % pre_order_spec.spec.name)
            pre_order_spec.spec.stock -= pre_order_spec.amount  # 更新库存
            if pre_order_spec.spec.discount:  # 如果优惠存在，优先使用优惠
                order_sum += pre_order_spec.amount * pre_order_spec.spec.discount
            else:
                order_sum += pre_order_spec.amount * pre_order_spec.spec.price
            all_deposit += pre_order_spec.amount * pre_order_spec.spec.deposit
            pre_order_spec.spec.save()
        datetime_now = now()
        order = Order.objects.create(user=request.user,
                                     remark=remark,
                                     address=address,
                                     sum=order_sum + all_deposit,
                                     delivery_datetime=delivery_datetime,
                                     delivery_deadline_datetime=delivery_deadline_datetime,
                                     created_datetime=datetime_now,
                                     out_order_id=generate_out_order_id(datetime_now),
                                     deposit=all_deposit)

        create_order_products(order, pre_order_specs)
        pre_order.delete()

        return Response(data=order_response_data(order))
    else:
        raise ValidationError(request_serializer.errors)


def create_order_products(order, pre_order_specs):
    for pre_order_spec in pre_order_specs:
        OrderProduct.objects.create(
            order=order,
            spec=pre_order_spec.spec,
            product_name=pre_order_spec.spec.product.name,
            spec_name=pre_order_spec.spec.name,
            price=pre_order_spec.spec.price,
            unit=pre_order_spec.spec.unit,
            amount=pre_order_spec.amount,
            image=pre_order_spec.spec.product.image,
            discount=pre_order_spec.spec.discount,
            deposit=pre_order_spec.spec.deposit,
            deposit_desc=pre_order_spec.spec.deposit_desc
        )


def order_response_data(order: Order):
    return {
        'detail': u"下单成功",
        'order_id': order.id,
        'sum': order.sum,
        'created_datetime': order.created_datetime,
        'expired_datetime': order.expired_datetime,
        'delivery_datetime': order.delivery_datetime,
        'pay_description': u'华焱农贸消费',
        'out_order_id': order.out_order_id
    }


@api_view(['GET'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def get_order_list(request: Request, order_status='0'):
    user = request.user
    # request_page = 1
    # serializer = OrderListRequestSerializer(data=request.data)
    # if serializer.is_valid():
    #     request_page = serializer.validated_data['page']
    order_status = [int(status) for status in order_status.split(',')]
    if 0 in order_status:
        orders = Order.objects.filter(user=user).order_by("-created_datetime")
    else:
        orders = Order.objects.filter(user=user, status__in=order_status).order_by("-created_datetime")
    # orders, has_more = get_page(orders, request_page)
    response_data = OrderListResponseSerializer({'orders': orders, 'has_more': False}).data
    return Response(response_data)


@api_view(['GET'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def get_order_detail(request: Request, order_id):
    try:
        order = Order.objects.get(pk=order_id)
    except Order.DoesNotExist:
        raise NotFound(detail=u'订单号%s不存在' % order_id)
    return order_to_dict(order)


@api_view(['PUT'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
@transaction.atomic()
def cancel_order_status(request: Request):
    serializer = OrderUpdateStatusSerializer(data=request.data)
    if serializer.is_valid():
        order = serializer.validated_data['order_id']
        if order.status == order_status.NOT_PAYED:  # 未支付订单
            order = Order.objects.select_for_update().get(user=request.user, id=order.id)
            products = order.products.all()
            specs = ProductSpec.objects.select_for_update().filter(id__in=products)
            for product in products:
                for spec in specs:
                    if spec.id == product.spec_id:
                        spec.stock += product.amount
                        spec.save()
            order.status = order_status.USER_CANCEL
            order.save()
            return Response({'detail': u'取消成功'})
        else:
            raise ValidationError(detail=u'订单不正确')
    else:
        raise ValidationError(serializer.errors)


@api_view(['DELETE'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def delete_order(request: Request, order_id):
    try:
        order = Order.objects.get(user=request.user, id=order_id)
    except Order.DoesNotExist:
        raise NotFound(detail=u'订单不存在')
    if order.status == order_status.FINISHED \
            or order_status == order_status.SYSTEM_CANCEL \
            or order_status == order_status.USER_CANCEL:
        order.delete()
        return Response({'detail': u'删除成功'})
    else:
        raise ValidationError(detail=u'订单无法删除')


@api_view(['PUT'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
@transaction.atomic()
def confirm_order(request: Request):
    serializer = OrderUpdateStatusSerializer(data=request.data)
    if serializer.is_valid():
        order = serializer.validated_data['order_id']
        if request.user != order.user or order.status != order_status.TO_BE_RECEIVED:
            raise ValidationError(detail=u'订单不正确')
        try:
            order = Order.objects.select_for_update().get(id=order.id,
                                                          user=request.user,
                                                          status=order_status.TO_BE_RECEIVED)
        except Order.DoesNotExist:
            raise ValidationError(detail=u'订单不正确')
        order.status = order_status.TO_RETURN_DEPOSIT if order.deposit > 0 else order_status.FINISHED
        order.save()
        return Response({'detail': u'确认收货成功'})
    else:
        raise ValidationError(serializer.errors)


@api_view(['PUT'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
@transaction.atomic()
def request_return_deposit(request: Request):
    serializer = OrderUpdateStatusSerializer(data=request.data)
    if serializer.is_valid():
        order = serializer.validated_data['order_id']
        if request.user != order.user or order.status != order_status.TO_RETURN_DEPOSIT:
            raise ValidationError(detail=u'订单不正确')
        try:
            order = Order.objects.select_for_update().get(id=order.id,
                                                          user=request.user,
                                                          status=order_status.TO_RETURN_DEPOSIT)
        except Order.DoesNotExist:
            raise ValidationError(detail=u'订单不正确')
        order.status = order_status.REQUEST_RETURN_DEPOSIT
        order.save()
        return Response({'detail': u'请求成功'})
    else:
        raise ValidationError(serializer.errors)


def order_to_dict(order: Order) -> dict:
    products = order.products.all()
    return {
        'order_id': order.id,
        'created_datetime': order.created_datetime,  # 订单创建时间
        'expired_datetime': order.expired_datetime,  # 订单过期时间
        'status': order.status,  # 订单状态
        'sum': order.sum,  # 金额
        'products': [product_to_dict(product) for product in products]
    }


def product_to_dict(product: OrderProduct) -> dict:
    return {
        'spec_id': product.spec_id,
        'name': product.product_name,
        'spec_name': product.spec_name,
        'price': product.price,
        'unit': product.unit,
        'amount': product.amount,
        'image': product.image_url
    }


def list_to_products(product_dict_list: list):
    return [dict_to_product(product_dict) for product_dict in product_dict_list]


def dict_to_product(product_dict: dict) -> OrderProduct:
    # product_id = product_dict['product_id']
    spec_id = product_dict['spec_id']
    amount = product_dict['amount']

    try:
        product_spec = ProductSpec.objects.get(pk=spec_id)
    except ProductSpec.DoesNotExist:
        raise ValidationError(detail=u'商品(%s)不存在' % spec_id)

    if not product_spec.is_on_shell:
        raise ValidationError(detail=u'商品(%s)已下架' % spec_id)

    if product_spec.stock < amount:
        raise ValidationError(detail=u'商品(%s)库存不足' % spec_id)

    order_product = OrderProduct(name=product_spec.product.name,
                                 spec=product_spec,
                                 spec_name=product_spec.spec_name,
                                 price=product_spec.price,
                                 unit=product_spec.unit,
                                 image=product_spec.product.image,
                                 amount=amount)

    # 更新库存
    product_spec.stock -= order_product.amount
    product_spec.save()

    return order_product


def dict_to_order(order_dict: dict, user: FMUser) -> Order:
    order = Order(user=user)  # 创建
    # order.expired_datetime = order.created_datetime + timedelta(days=3)  # 默认订单不会过期
    if 'remark' in order_dict and order_dict['remark']:  # 备注
        order.remark = order_dict['remark']
    order.save()  # 保存订单
    products = list_to_products(order_dict['products'])
    for product in products:
        product.order = order
        product.save()  # 保存订单对应的商品
        order.sum += product.price * int(product.amount)
    order.save()  # 更新订单金额
    return order


@api_view(['GET'])
@authentication_classes((BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def get_sales_order(request: Request):
    user = request.user
    if user.user_type == USER_TYPE_SALES:
        queryset = Order.objects.filter(user__sales=user)
        serializer = OrderResponseSerializer(queryset)
        return Response(serializer.data)
    else:
        raise ValidationError(detail=u'当前用户不是销售')
